from gear import HiddenPrints, PrintToTxt, GearInit, PlanetInit, Gear, PlanetaryGear
import numpy as np
from math import sin, cos, tan, radians, degrees, floor, sqrt, acos, atan, pi,asin
import gongcha as gc
'''
从公法线计算回差
'''


# 输入公法线、量柱球测量距上下偏差
class InputEb(object):
    def __init__(self, Es1, Ei1, Es3, Ei3, Es2, Ei2, Emeasure=['Eb', 'Eb', 'Ey']):
        '''
        :param Es1:太阳轮公法线/量柱上偏差
        :param Ei1:太阳轮公法线/量柱下偏差
        :param Es3:行星轮公法线/量柱上偏差
        :param Ei3:行星轮公法线/量柱下偏差
        :param Es2:内齿轮量柱上偏差
        :param Ei2:内齿轮量柱下偏差
        :param Emeasure:表示齿轮各自齿厚的控制测量方法，Eb：公法线，Ey：量柱
        '''
        self.Es1 = Es1  # 上偏差
        self.Ei1 = Ei1  # 下偏差
        self.Em1 = -abs((Es1 + Ei1)/2)  # 平均偏差
        self.dE1 = abs(Es1 - Ei1)  # 公差

        self.Es3 = Es3
        self.Ei3 = Ei3
        self.Em3 = -abs((Es3 + Ei3)/2)
        self.dE3 = abs(Es3 - Ei3)

        self.Es2 = Es2
        self.Ei2 = Ei2
        self.Em2 = -abs((Es2 + Ei2)/2) # 可能输入的偏差对于内齿轮来说是正值
        self.dE2 = abs(Es2 - Ei2)

        self.Emeasure = Emeasure
def cx_Fr(pt:PlanetaryGear): 
    g13 = pt.gear_ac  # 太阳轮-行星轮
    g32 = pt.gear_cb  # 行星轮-内齿圈
    
    alpha = pt.alpha  # 压力角
    alpha13 = g13.alpha_work  # 啮合角
    alpha32 = g32.alpha_work  # 啮合角
    errF1 = gc.F_r(g13.d1, pt.m, pt.PlanetInitStruct.it1)
    errF3 = gc.F_r(g13.d2, pt.m, pt.PlanetInitStruct.it3)
    errF2 = gc.F_r(g32.d2, pt.m, pt.PlanetInitStruct.it2)
    print(errF1,errF2,errF3)
    # 太阳轮+行星轮径向跳动误差/径向综合公差引起的侧隙公差
    T1_Fr = ((errF1+errF3) * tan(alpha13))*2
    # 内齿轮+行星轮径向跳动误差/径向综合公差引起的侧隙公差
    T2_Fr = ((errF2+errF3) * tan(alpha32))*2
    
    return (T1_Fr/2,-T1_Fr/2),(T2_Fr/2,-T2_Fr/2)#齿轮副13侧隙改变量的（上偏差，下偏差），齿轮副32侧隙改变量的（上偏差，下偏差）

# 齿轮固有误差
def cx_gear(pt: PlanetaryGear, Ebin: InputEb):
    '''
    :param pt:行星齿轮类
    :param Ebin:输入偏差类
    齿轮固有误差导致的侧隙（公法线+径跳）
    包含：公法线/量柱测量距偏差；径向跳动或径向综合偏差
    :return:齿轮固有误差导致的侧隙均值（单级圆周侧隙j_t，线值），及其公差（6倍标准差）
    '''
    g13 = pt.gear_ac  # 太阳轮-行星轮
    g32 = pt.gear_cb  # 行星轮-内齿圈
    beta=pt.gear_ac.betab
    alpha = pt.alpha  # 压力角
    alphat = pt.gear_ac.alphat
    betab = asin(sin(pt.beta)*cos(alpha))
    alpha13 = g13.alpha_work  # 啮合角
    alpha32 = g32.alpha_work  # 啮合角

    if Ebin.Emeasure[0] == 'Eb':
        cx1_E = -Ebin.Em1/cos(alpha)  # 太阳轮·公法线·偏差引起的侧隙
        dx1_E = Ebin.dE1/(6*cos(alpha))  # 太阳轮·公法线·公差引起的侧隙标准差
    else:
        cx1_E = -Ebin.Em1/cos(alphat)*cos(betab)*sin(pt.alphatm[0]) # 太阳轮·量柱距·偏差引起的侧隙
        dx1_E = Ebin.dE1/6/cos(alphat)*cos(betab)*sin(pt.alphatm[0])  # 太阳轮·量柱距·公差引起的侧隙标准差
        if pt.za%2 == 1:
            cx1_E*=cos(pi/2/pt.za)
            dx1_E*=cos(pi/2/pt.za)

    if Ebin.Emeasure[1] == 'Eb':
        cx3_E = -Ebin.Em3/cos(alpha)  # 行星轮·公法线·偏差引起的侧隙
        dx3_E = Ebin.dE3/(6*cos(alpha))  # 行星轮·公法线·公差引起的侧隙标准差
    else:
        cx3_E = -Ebin.Em3/cos(alphat)*cos(betab)*sin(pt.alphatm[1])  # 行星轮·量柱距·偏差引起的侧隙
        dx3_E = Ebin.dE3/6/cos(alphat)*cos(betab)*sin(pt.alphatm[1])  # 行星轮·量柱距·公差引起的侧隙标准差
        if pt.zc%2 == 1:
            cx3_E*=cos(pi/2/pt.zc)
            dx3_E*=cos(pi/2/pt.zc)
    #alpha = g13.alpha  # 压力角
    if Ebin.Emeasure[2] == 'Eb':
        cx2_E = -Ebin.Em2/cos(alpha)  # 内齿轮·公法线·偏差引起的侧隙
        dx2_E = Ebin.dE2/(6*cos(alpha))  # 内齿轮·公法线·公差引起的侧隙标准差
    else:
        cx2_E = -Ebin.Em2/cos(alphat)*cos(betab)*sin(pt.alphatm[2])  # 内齿轮·量柱距·偏差引起的侧隙
        dx2_E = Ebin.dE2/6/cos(alphat)*cos(betab)*sin(pt.alphatm[2])  # 内齿轮·量柱距·公差引起的侧隙标准差
        if pt.zb%2 == 1:
            cx2_E*=cos(pi/2/pt.zb)
            dx2_E*=cos(pi/2/pt.zb)
        
        #cx2_E = -Ebin.Em2*tan(alpha)  # 内齿轮·量柱距·偏差引起的侧隙
        #dx2_E = Ebin.dE2/6*tan(alpha)  # 内齿轮·量柱距·公差引起的侧隙标准差
    
    print(cx2_E+dx2_E*3,cx2_E-dx2_E*3)

    
    #print(((cx1_E, dx1_E), (cx2_E, dx2_E), (cx3_E, dx3_E), (cx1_Fr, dx1_Fr), (cx2_Fr, dx2_Fr)))
    #return (cx1_E+cx3_E)*cos(alpha)/cos(alpha13)+(cx3_E+cx2_E)*cos(alpha)/cos(alpha32),\
    #    ((dx1_E+dx3_E)*cos(alpha)/cos(alpha13)+(dx3_E+dx2_E*cos(alpha)/cos(alpha32)))*6
    '''
    print((cx1_E+dx1_E*3)*cos(alpha)/cos(alpha)/cos(beta))
    print((cx3_E+dx3_E*3)*cos(alpha)/cos(alpha)/cos(beta))
    print((cx2_E+dx2_E*3)*cos(alpha)/cos(alpha)/cos(beta))
    '''
    cxm13 = (cx1_E+cx3_E)*cos(alpha)/cos(alpha13)/cos(beta)
    cxm32 = (cx3_E+cx2_E)*cos(alpha)/cos(alpha32)/cos(beta)
    Tcx13 = (dx1_E+dx3_E)*cos(alpha)/cos(alpha13)*6/cos(beta)
    Tcx32 = (dx3_E+dx2_E)*cos(alpha)/cos(alpha32)*6/cos(beta)
    print((cxm13+Tcx13/2,cxm13-Tcx13/2),(cxm32+Tcx32/2,cxm32-Tcx32/2))
    #齿轮副13侧隙改变量的（上偏差，下偏差），齿轮副32侧隙改变量的（上偏差，下偏差）
    return (cxm13+Tcx13/2,cxm13-Tcx13/2),(cxm32+Tcx32/2,cxm32-Tcx32/2)


def cx_fxfy(pt: PlanetaryGear):
    '''
    对于小模数，按照GB/T2363-90选择fx和fy
    对于中大模数，按照fx=F_beta,fy=0.5*fx的原则选取 
    fx和fy最后取太阳轮和行星轮的平行度公差综合来计算
    根据最高的精度等级计算
    :return:平行度偏差引起的侧隙及其公差（6倍标准差）
    '''
    it = min([pt.PlanetInitStruct.it1,pt.PlanetInitStruct.it3,pt.PlanetInitStruct.it2])
    alpha = pt.gear_ac.alpha
    fx1, fy1 = gc.fxfy(pt.gear_ac.d1, pt.m, pt.b1,
                       it)  # 太阳轮平行度公差
    fx3, fy3 = gc.fxfy(pt.gear_ac.d2, pt.m, pt.b3,
                       it)  # 行星轮平行度公差
    fx2, fy2 = gc.fxfy(pt.gear_cb.d2, pt.m, pt.b2,
                       it)  # 内齿轮平行度公差
    #print(fx1,fx3,fx2,fy1,fy3,fy2)
    
    Tfxfy = fx3   # 平行度偏差引起的侧隙均值
    print(fx3)
    #dx_fx = 1/3 * fy3  #平行度偏差引起的侧隙标准差


    return (0, -Tfxfy),(0, -Tfxfy)

def cx_fa(pt:PlanetaryGear,dfa=[]):#中心距误差
    '''
    :param fa:输入一个列表，上下偏差为中心距上下偏差[fa_s,fa_i],如果没有输入则为None，程序从标准中查找中心距公差(此处要求fa_s>=fa_i)
    :return:中心距误差引起的侧隙均值和方差
    '''
    if dfa!=[]:#指定dfa
        
        fam = (dfa[0]+dfa[1])/2 # 中心距偏差均值
        Tfa = abs(dfa[0]-dfa[1]) # 中心距方差值
    else:
        #查中心距公差 老GB
        #print('xxxx')
        
        Tfa=0
        pass
    
    #T_dfa = 2*dfa*(tan(pt.gear_ac.alpha_work)+tan(pt.gear_cb.alpha_work))
    T_dfa1 = 2 * Tfa*tan(pt.gear_ac.alpha_work)
    T_dfa2 = 2 * Tfa*tan(pt.gear_cb.alpha_work)
    return (T_dfa1/2,-T_dfa1/2), (T_dfa2/2,-T_dfa2/2)#齿轮副13侧隙改变量的（上偏差，下偏差），齿轮副32侧隙改变量的（上偏差，下偏差）

def cx_carrier_pt(pt:PlanetaryGear,dfa=[]):
    if dfa!=[]:#给定fa
        Tfa = abs(dfa[0]-dfa[1]) # 中心距方差值，相当于行星架节距偏差值
    else:
        #查中心距公差 老GB
        #print('xxxx')
        Tfa = 0
        pass
    
    cx = -Tfa*2
    return cx  #对总侧隙最后改变的量


def ptcx(pt:PlanetaryGear,Ebin:InputEb,dfa=[0,0],fa=False,Fr=True,fxfy=True): # 对各种侧隙的加和,不包括行星架偏差
    '''
    计算单个行星齿轮的总侧隙及公差
    :return:cx,dx
    '''
    dx_13_s=0#侧隙上偏差
    dx_13_i=0#侧隙下偏差
    dx_32_s=0#侧隙上偏差
    dx_32_i=0#侧隙下偏差
    
    #Fr,fa,fxfy对上下偏差的影响
    dxj_13_s=0
    dxj_13_i=0
    dxj_32_s=0
    dxj_32_i=0
    tmp = cx_gear(pt, Ebin)# 齿轮固有偏差侧隙
    dx_13_s+=tmp[0][0]
    dx_13_i+=tmp[0][1]
    dx_32_s+=tmp[1][0]
    dx_32_i+=tmp[1][1]
    
    if Fr:
        tmp = cx_Fr(pt)# 齿轮固有偏差侧隙
        dxj_13_s+=tmp[0][0]
        dxj_13_i+=tmp[0][1]
        dxj_32_s+=tmp[1][0]
        dxj_32_i+=tmp[1][1]
    if fa:
        tmp = cx_fa(pt,dfa=dfa)
        dxj_13_s+=tmp[0][0]
        dxj_13_i+=tmp[0][1]
        dxj_32_s+=tmp[1][0]
        dxj_32_i+=tmp[1][1]
    
    if fxfy:
        tmp = cx_fxfy(pt)# 平行度误差侧隙
        dxj_13_i = -sqrt(dxj_13_i**2+tmp[0][1]**2)
        dxj_32_i = -sqrt(dxj_32_i**2+tmp[1][1]**2)
    
    dx_13_s+=dxj_13_s
    dx_13_i+=dxj_13_i
    dx_32_s+=dxj_32_s
    dx_32_i+=dxj_32_i
    
    
        
    '''
    if carrier:
        tmp = cx_carrier_pt(pt,fa=fa)
        dx_13_s+=tmp/2
        dx_13_i+=tmp/2
        dx_32_s+=tmp/2
        dx_32_i+=tmp/2
    '''
    
    
    return (dx_13_s,dx_13_i),(dx_32_s,dx_32_i)#两个齿轮副分别的：（侧隙最大值，侧隙最小值）

    


def cx2pthc(dxsi13,dxsi32, pt: PlanetaryGear, output='out',calcangle=0,carrier=True,fa=False,dfa=[0,0]):
    '''
    :param dxsi13:13副侧隙最大最小值
    :param dxsi32:32副侧隙最大最小值
    :param pt:单级行星齿轮
    :param output:'out'/'in'，折算到输出轴/输入轴
    :param calcangle:0/1，0:压力角折算，1：啮合角折算。（圆周侧隙为节圆上的侧隙）
    :return:单级行星齿轮折算到输出/输入轴的回程间隙pthc（回差）的最大值和最小值
    '''
    a=pt.gear_ac.alphat
    aw=pt.gear_ac.alpha_work
    if calcangle==0:
        aw=a
    if carrier and fa:#中心距误差存在时才有行星架节距误差
        tmp = cx_carrier_pt(pt,dfa=dfa)
    else:
        tmp=0
    
    pthc_in_max = (dxsi13[0]+dxsi32[0]+tmp)*180*60/pi/1000/(0.5*pt.gear_ac.m*pt.za*cos(a)/cos(aw))  # 折算到太阳轮（输入轴）的回差（计入行星架节距偏差）
    pthc_in_min = (dxsi13[1]+dxsi32[1]+tmp)*180*60/pi/1000/(0.5*pt.gear_ac.m*pt.za*cos(a)/cos(aw))
    if output == 'in':
        return pthc_in_max,pthc_in_min
    else:
        return pthc_in_max/pt.i, pthc_in_min/pt.i # 折算到行星架（输出轴）的回差



def pthc2allhc(ptlist,Ebinlist,dfalist=[],falist=[],carrier=True,calcangle=0,Fr=True,fxfy=True,returneverycx=False):
    '''
    :param ptlist:各行星齿轮列表，从第一级开始（[pt,pt,...]）
    :param Ebinlist:公法线/量柱测量距偏差列表，从第一级开始（[Ebin,Ebin,...]）
    fa表示启用中心距偏差
    dfa表示中心距上下偏差，如果为[]则表示未指定
    :return:多级行星齿轮折算到末级输出轴的回差allhc（arcmin）的最大最小值
    '''
    lenpt = len(ptlist)
    
    
    if dfalist==[]:
        for i in range(lenpt):
            dfalist.append([])
    if falist==[]:
        for i in range(lenpt):
            falist.append(False)
    
    
    
    pthclist_si = []#各输出轴回差最大值最小值
    pt_i = []
    for i in range(lenpt):
        pt_i.append(ptlist[i].i)  # 各级行星齿轮的传动比
        if falist==None:
            dxsi13,dxsi32 = ptcx(ptlist[i],Ebinlist[i],dfa=dfalist[i],fa=falist[i],Fr=Fr,fxfy=fxfy) # 单级总侧隙均值、方差
        else:
            dxsi13,dxsi32 = ptcx(ptlist[i],Ebinlist[i],dfa=dfalist[i],fa=falist[i],Fr=Fr,fxfy=fxfy) # 单级总侧隙均值、方差
        pthc_in_max,pthc_in_min = cx2pthc(dxsi13, dxsi32, ptlist[i],calcangle=calcangle,carrier=carrier,dfa=dfalist[i],fa=falist[i]) # 转化到单级总回差、方差（输出轴）
        pthclist_si.append([pthc_in_max,pthc_in_min])
            
    pthclist_si_divide_i = []#存储经过折算的回差，即每一级对总回差的贡献
    allhc_max = 0
    allhc_min = 0
    iall = 1
    for i in range(lenpt-1, -1, -1):
        tmpmax = pthclist_si[i][0]/iall
        tmpmin = pthclist_si[i][1]/iall
        pthclist_si_divide_i.append([tmpmax,tmpmin])
        allhc_max += tmpmax
        allhc_min += tmpmin
        iall *= pt_i[i]
    pthclist_si_divide_i.reverse()
    if returneverycx:
        return pthclist_si,pthclist_si_divide_i,[allhc_max,allhc_min]
    else:
        return allhc_max,allhc_min



if __name__ == '__main__':
    ptinit = PlanetInit(Dm=[None,None,None])
    #pt = PlanetaryGear(0.45, 12, 36, 84, 0, 0, 0, ptinit)
    pt = PlanetaryGear(1.75, 18, 45, 108, 0.393, 0.0285, 0.45, ptinit)
    ieb = InputEb(-56, -83, -76, -108, 394, 207, Emeasure=['Eb', 'Eb', 'Ey'])
    
    #print(pt.Dm)
    #print('aw;',degrees(pt.gear_cb.alpha_work))
    
    print(pt.E[2],pt.E[2]+394/1000,pt.E[2]+207/1000)
    print('--')
    
    pthc_max,pthc_min=pthc2allhc([pt], [ieb],carrier=False,calcangle=0,Fr=False,fxfy=False,dfalist=[],falist=[])
    #pthc_max,pthc_min=pthc2allhc([pt], [ieb],dfalist=[[6.5,-6,5]],falist=[True],carrier=True,calcangle=0,Fr=False,fxfy=False)
    print(pthc_max,pthc_min)
    
    print(pthc_max/60,pthc_min/60)
    
